xtask\tasks\fuzz/
cargo_fuzz.rs1use anyhow::Context;
7use std::path::Path;
8use std::path::PathBuf;
9
10pub(super) enum CargoFuzzCommand {
11 Build,
12 Run { artifact: Option<PathBuf> },
13 Fmt { input: PathBuf },
14 Cmin,
15 Tmin { test_case: PathBuf },
16 Coverage,
17}
18
19impl CargoFuzzCommand {
20 fn to_args<'a, 'b: 'a>(&'b self, target: &'a str) -> Vec<&'a str> {
21 match self {
22 CargoFuzzCommand::Build => {
23 vec!["build", target]
24 }
25 CargoFuzzCommand::Run { artifact } => {
26 let mut args = vec!["run", target];
27 if let Some(artifact) = artifact {
28 args.push(artifact.to_str().unwrap())
29 }
30 args
31 }
32 CargoFuzzCommand::Fmt { input } => {
33 vec!["fmt", target, input.to_str().unwrap()]
34 }
35 CargoFuzzCommand::Cmin => {
36 vec!["cmin", target]
37 }
38 CargoFuzzCommand::Tmin { test_case } => {
39 vec!["tmin", target, test_case.to_str().unwrap()]
40 }
41 CargoFuzzCommand::Coverage => {
42 vec!["coverage", target]
43 }
44 }
45 }
46
47 pub(super) fn invoke(
48 self,
49 target_name: &str,
50 fuzz_dir: &Path,
51 target_options: &[String],
52 toolchain: Option<&str>,
53 extra: &[String],
54 ) -> anyhow::Result<()> {
55 if which::which("cargo-fuzz").is_err() {
56 anyhow::bail!("could not find cargo-fuzz! did you run `cargo install cargo-fuzz`?");
57 }
58
59 let sh = xshell::Shell::new()?;
60 if matches!(&self, CargoFuzzCommand::Run { artifact: Some(_) }) {
61 sh.set_var("XTASK_FUZZ_REPRO", "1");
62 }
63
64 let mut toolchain_check_cmd = xshell::cmd!(sh, "rustc");
65 if let Some(toolchain_override) = toolchain {
66 toolchain_check_cmd = toolchain_check_cmd.arg(format!("+{}", toolchain_override));
67 }
68 let result = toolchain_check_cmd
69 .arg("-V")
70 .output()
71 .context("could not detect toolchain! did you run `rustup toolchain install`?")?;
72 let output = std::str::from_utf8(&result.stdout)?.to_ascii_lowercase();
73 let is_nightly = output.contains("-nightly") || output.contains("-dev");
74
75 let mut cmd = xshell::cmd!(sh, "cargo");
76 if let Some(toolchain_override) = toolchain {
77 cmd = cmd.arg(format!("+{}", toolchain_override));
78 }
79 cmd = cmd.arg("fuzz");
80 cmd = cmd.args(self.to_args(target_name));
81 cmd = cmd.arg("--fuzz-dir").arg(fuzz_dir);
82
83 if is_nightly {
84 } else if std::env::var_os("CARGO").is_some() {
86 log::warn!(
90 "Running on a stable toolchain in a `cargo xtask` invocation, disabling sanitizers"
91 );
92 log::warn!(
93 "To enable sanitizers, run {} directly, or switch to a nightly toolchain",
94 std::env::current_exe()?.display()
95 );
96 cmd = cmd.args(["-s", "none"]);
97 } else {
98 log::warn!("Running on a stable toolchain, enabling sanitizers via RUSTC_BOOTSTRAP");
100 cmd = cmd.env("RUSTC_BOOTSTRAP", "1");
101 }
102
103 cmd = cmd.args(extra);
104 if self.supports_target_options() && !target_options.is_empty() {
105 if !extra.iter().any(|x| x == "--") {
106 cmd = cmd.arg("--");
107 }
108 cmd = cmd.args(target_options);
109 }
110
111 cmd.run()?;
112
113 Ok(())
114 }
115
116 fn supports_target_options(&self) -> bool {
117 matches!(self, CargoFuzzCommand::Run { .. })
118 }
119}